package com.bc.trade.model;


import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import com.bc.common.CommonEnum.NotifyStatus;
import com.bc.common.CommonEnum.OrderStatus;
import com.bc.common.PayType;
import com.bc.common.basemodel.BaseTradeOrder;
import com.bc.common.message.AppidPayReq;
import com.bc.common.message.AppidWxgjPayReq;
import com.bc.common.message.DFReq;
import com.bc.common.message.TransferQrcodeReq;
import com.bc.trade.message.QrcodeReq;
import com.bc.trade.message.QuickPaySetReq;
import com.bc.trade.message.RefundReq;
import com.bc.trade.message.UnionPayReq;
import com.bc.trade.service.CalcFeeService;
import com.bc.trade.vo.TradeElement;
import com.fs.common.extend.FSSqlHelper;
import com.fs.common.util.FSDate;
import com.fs.common.util.FSIDGenerate;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;

@SuppressWarnings("serial")
public class TradeOrder extends BaseTradeOrder<TradeOrder> {
	
	public static final TradeOrder dao = new TradeOrder().dao();
	
	public TradeOrder selectByRemark(String remark) {
		String time = LocalDateTime.now().minusHours(2).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		return super.findFirst(
				"select * from trade_order where channelOrderNo = ? and createTime > ? and orderStatus=?",
				remark, time, OrderStatus.Create.getValue());
	}
	
	public TradeOrder selectByOrderNo(String orderNo){
		return super.findFirst("select * from trade_order where orderNo = ?",orderNo);
	}
	
	public TradeOrder selectByOrderNoForUpdate(String orderNo) {
		return super.findFirst("select * from trade_order where orderNo = ? for update",orderNo);
	}
	
	public TradeOrder selectByMerchOrderNo(String merchCode, String merchOrderNo) {
		return super.findFirst("select * from trade_order where merchCode = ? and merchOrderNo = ?",merchCode,merchOrderNo);
	}
	
	public boolean orderExist(String merchCode,String merchOrderNo){
		return Db.queryLong("select count(0) from trade_order where merchCode = ? and merchOrderNo = ?",merchCode,merchOrderNo) > 0;
	}
	
	public void updateNotifyStatus(String orderNo, String notifyStatus) {
		Db.update("update trade_order set notifyStatus = ? where orderNo = ?", notifyStatus,orderNo);
	}
	
	
	
	/**
	 * 查询总交易金额
	 * @param merchCode
	 * @return
	 */
	public Long querySumAmountDate(String myDate){
		FSSqlHelper sql = new FSSqlHelper("SELECT SUM(amount) FROM trade_order ");
		sql.equals("settleDate", myDate);
		sql.equals("orderStatus",OrderStatus.Success.getValue());
		BigDecimal temp = Db.queryBigDecimal(sql.toString(), sql.getParams());
		if(temp == null){
			return 0L;
		}
		Long sumAmount = temp.longValue();
		return sumAmount;
	}
	
	/**
	 * 查询总交易金额
	 * @param merchCode
	 * @return
	 */
	public Long querySumAmount(String merchCode){
		FSSqlHelper sql = new FSSqlHelper("SELECT SUM(amount) FROM trade_order ");
		sql.equals("merchCode", merchCode);
		sql.equals("settleDate", FSDate.getDateNumber());
		sql.equals("orderStatus",OrderStatus.Success.getValue());
		BigDecimal temp = Db.queryBigDecimal(sql.toString(), sql.getParams());
		if(temp == null){
			return 0L;
		}
		Long sumAmount = temp.longValue();
		return sumAmount;
	}
	
	/**
	 * 商户当前总交易金额
	 * 
	 * @param merchCode
	 * @return
	 */
	public Long sumAmount(String merchCode) {
		String sql = "SELECT SUM(amount) FROM trade_order WHERE merchCode = ? AND orderStatus = ?";
		BigDecimal sumAmount = Db.queryBigDecimal(sql, merchCode, OrderStatus.Success.getValue());
		if(sumAmount == null) {
			sumAmount = BigDecimal.ZERO;
		}
		return sumAmount.longValue();
	}

	/**
	 * 商户当前支付类别总交易金额
	 * 
	 * @param merchCode
	 * @param payType
	 * @param settleDate
	 * @return
	 */
	public Long sumPayTypeAmount(String merchCode, String payType, String settleDate) {
		String sql = "select SUM(amount) from trade_order where merchCode = ? and payType = ? and settleDate = ? and orderStatus = ?";
		BigDecimal sumAmount = Db.queryBigDecimal(sql, merchCode, payType, settleDate, OrderStatus.Success.getValue());
		if(sumAmount == null) {
			sumAmount = BigDecimal.ZERO;
		}
		return sumAmount.longValue();
	}

	/**
	 * 商户当前总交易金额
	 * 
	 * @param merchCode
	 * @param settleDate
	 * @return
	 */
	public Long sumOrderAmount(String merchCode, String settleDate) {
		String sql = "select sum(amount) from trade_order where merchCode = ? and settleDate = ? and orderStatus = ?";
		BigDecimal sumAmount = Db.queryBigDecimal(sql, merchCode, settleDate, OrderStatus.Success.getValue());
		if(sumAmount == null) {
			sumAmount = BigDecimal.ZERO;
		}
		return sumAmount.longValue();
	}

	public static TradeOrder createUnionpay(UnionPayReq req,TradeElement tradeElement){
		CalcFeeService feeService = new CalcFeeService();
		Integer merchFee = feeService.getFee(Integer.valueOf(req.getAmount()), tradeElement.getTradeStrategy().getMerchFeeId());
		TradeOrder tradeOrder = new TradeOrder();
		tradeOrder.setId(FSIDGenerate.getUUID());
		tradeOrder.setOrderNo(FSIDGenerate.nextOrderNo());
		tradeOrder.setOrgCode(req.getOrgCode());
		tradeOrder.setMerchOrderNo(req.getMerchOrderNo());
		tradeOrder.setMerchCode(req.getMerchCode());
		tradeOrder.setPayType(req.getPayType());
		tradeOrder.setAmount(Integer.valueOf(req.getAmount()));
		tradeOrder.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		tradeOrder.setMerchFee(merchFee);
		tradeOrder.setBalance(0L);
		tradeOrder.setSettleDate(FSDate.getDate());
		tradeOrder.setCreateTime(FSDate.getDateTime());
		tradeOrder.setNotifyStatus(NotifyStatus.Wait.getValue());
		tradeOrder.setNotifyUrl(req.getNotifyUrl());
		tradeOrder.setCardType(req.getCardType());
		tradeOrder.setReturnUrl(req.getCallbackUrl());
		tradeOrder.setIsInVirtualAccount(false);
		tradeOrder.setRemark(req.getRemark());
		tradeOrder.setGoodsName(req.getGoodsName());
		return tradeOrder;
	}
	
	public static TradeOrder quickPaySet(QuickPaySetReq req,TradeElement tradeElement){
		CalcFeeService feeService = new CalcFeeService();
		Integer merchFee = feeService.getFee(Integer.valueOf(req.getAmount()), tradeElement.getTradeStrategy().getMerchFeeId());
		TradeOrder tradeOrder = new TradeOrder();
		tradeOrder.setId(FSIDGenerate.getUUID());
		tradeOrder.setOrderNo(FSIDGenerate.nextOrderNo());
		tradeOrder.setOrgCode(req.getOrgCode());
		tradeOrder.setMerchOrderNo(req.getMerchOrderNo());
		tradeOrder.setMerchCode(req.getMerchCode());
		if ("1".equals(req.getCardType())) {
			tradeOrder.setPayType(PayType.QUICK_PAY_CREDIT);
		} else {
			tradeOrder.setPayType(req.getPayType());
		}
		tradeOrder.setAmount(Integer.valueOf(req.getAmount()));
		tradeOrder.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		tradeOrder.setMerchFee(merchFee);
		tradeOrder.setBalance(0L);
		tradeOrder.setSettleDate(FSDate.getDate());
		tradeOrder.setCreateTime(FSDate.getDateTime());
		tradeOrder.setNotifyStatus(NotifyStatus.Wait.getValue());
		tradeOrder.setNotifyUrl(req.getNotifyUrl());
		tradeOrder.setCardType(req.getCardType());
		tradeOrder.setIsInVirtualAccount(false);
		tradeOrder.setRemark(req.getRemark());
		tradeOrder.setGoodsName(req.getGoodsName());
		return tradeOrder;
	}
	
	public static TradeOrder createRefund(RefundReq req,TradeOrder orignOrder){
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setOrderNo(FSIDGenerate.nextOrderNo());
		order.setOrgCode(req.getOrgCode());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setMerchCode(req.getMerchCode());
		order.setPayType(req.getPayType());
		order.setOriginalOrderNo(orignOrder.getOrderNo());
		order.setAmount(0-Integer.parseInt(req.getAmount()));//退款金额
		order.setChannelCode(orignOrder.getChannelCode());
		order.setMerchFee(0);
		order.setBalance(0L);
		order.setSettleDate(FSDate.getDate());
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setCardType(orignOrder.getCardType());
		order.setIsInVirtualAccount(false);
		order.setRemark(req.getRemark());
		return order;
	}
	
	public static TradeOrder createDF(DFReq req,TradeElement tradeElement){
		CalcFeeService feeService = new CalcFeeService();
		Integer merchFee = feeService.getFee(Integer.valueOf(req.getAmount()), tradeElement.getTradeStrategy().getMerchFeeId());
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setOrderNo(FSIDGenerate.nextOrderNo());
		order.setOrgCode(req.getOrgCode());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setMerchCode(req.getMerchCode());
		order.setPayType(req.getPayType());
		order.setAmount(Integer.valueOf(req.getAmount()));
		order.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		order.setMerchFee(merchFee);
		order.setBalance(0L);
		order.setSettleDate(FSDate.getDate());
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setCustomerName(req.getAccountName());
		order.setBankCardNo(req.getAccountCardNo());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setIsInVirtualAccount(false);
		order.setRemark(req.getRemark());
		return order;
	}
	
	/**
	 * 生成扫码订单对象，并根据支付方式获取子商户号
	 * 
	 * @param req
	 * @param tradeStrategy
	 * @param payType
	 * @return
	 */
	public TradeOrder saveQrcodeOrder(QrcodeReq req,TradeElement tradeElement) {
		String goodsName = StrKit.isBlank(req.getGoodsName()) ? "收银商品" : req.getGoodsName();
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		order.setOrgCode(req.getOrgCode());
		order.setMerchCode(req.getMerchCode());
		order.setOrderNo(FSIDGenerate.nextOrderNo());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setPayType(req.getPayType());
		order.setOrderStatus(OrderStatus.Unknow.getValue());
		order.setAmount(Integer.valueOf(req.getAmount()));
		order.setCoinType(req.getCoinType());
		order.setMerchFee(new CalcFeeService().getFee(order.getAmount(), tradeElement.getTradeStrategy().getMerchFeeId()));
		order.setGoodsName(goodsName);
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setSettleDate(FSDate.getDate());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setRemark(req.getRemark());
		order.save();
		return order;
	}
	
	/**
	 * 生成转账二维码支付订单
	 * 
	 * @param req
	 * @param tradeStrategy
	 * @param payType
	 * @return
	 */
	public TradeOrder createTransferQrcodeOrder(TransferQrcodeReq req,TradeElement tradeElement) {
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		order.setOrgCode(req.getOrgCode());
		order.setMerchCode(req.getMerchCode());
		order.setOrderNo(FSIDGenerate.nextOrderNo());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setPayType(req.getPayType());
		order.setOrderStatus(OrderStatus.Create.getValue());
		order.setAmount(Integer.valueOf(req.getAmount()));
		order.setMerchFee(new CalcFeeService().getFee(order.getAmount(), tradeElement.getTradeStrategy().getMerchFeeId()));
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setSettleDate(FSDate.getDate());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setIsInVirtualAccount(false);
		order.setIsD0(false);
		return order;
	}
	
	/**
	 * 生成支付宝服务窗及微信公众号订单
	 * 
	 * @param req
	 * @param tradeStrategy
	 * @param payType
	 * @return
	 */
	public TradeOrder createAppidPayOrder(AppidPayReq req,TradeElement tradeElement) {
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		order.setOrgCode(req.getOrgCode());
		order.setMerchCode(req.getMerchCode());
		order.setOrderNo(FSIDGenerate.nextOrderNo());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setPayType(req.getPayType());
		order.setOrderStatus(OrderStatus.Create.getValue());
		order.setAmount(Integer.valueOf(req.getAmount()));
		int merchFee = new CalcFeeService().getFee(order.getAmount(), tradeElement.getTradeStrategy().getMerchFeeId());
		// 小于100元的交易加一元手续费
		if(order.getAmount() < 10000) {
			merchFee = merchFee + 100;
		}
		order.setMerchFee(merchFee);
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setSettleDate(FSDate.getDate());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setIsInVirtualAccount(false);
		order.setIsD0(false);
		return order;
	}
	
	/**
	 * 跨境微信公众号订单
	 * 
	 * @param req
	 * @param tradeStrategy
	 * @param payType
	 * @return
	 */
	public TradeOrder createAppidWxgjPayOrder(AppidWxgjPayReq req,TradeElement tradeElement) {
		TradeOrder order = new TradeOrder();
		order.setId(FSIDGenerate.getUUID());
		order.setChannelCode(tradeElement.getTradeStrategy().getChannelCode());
		order.setOrgCode(req.getOrgCode());
		order.setMerchCode(req.getMerchCode());
		order.setOrderNo(tradeElement.getMerch().getCointype()+FSIDGenerate.nextOrderNo());
		order.setMerchOrderNo(req.getMerchOrderNo());
		order.setPayType(req.getPayType());
		order.setOrderStatus(OrderStatus.Create.getValue());
		order.setAmount(Integer.valueOf(req.getAmount()));
		order.setTotalFee(order.getAmount());
		order.setMerchFee(new CalcFeeService().getFee(order.getAmount(), tradeElement.getTradeStrategy().getMerchFeeId()));
		order.setCreateTime(FSDate.getDateTime());
		order.setNotifyUrl(req.getNotifyUrl());
		order.setReturnUrl(req.getCallbackUrl());
		order.setSettleDate(FSDate.getDate());
		order.setNotifyStatus(NotifyStatus.Wait.getValue());
		order.setIsInVirtualAccount(false);
		order.setIsD0(false);
		order.setOpenid(req.getOpenid());
		order.setSubAppid(req.getSub_appid());
		order.setSubOpenid(req.getSub_openid());
		if(null!=req.getRemark() && 0<req.getRemark().length()) {
			order.setRemark(req.getRemark());
		}
		order.setCoinType(tradeElement.getMerch().getCointype());//交易清算币种
		order.setOtherMerchCode(tradeElement.getTradeStrategy().getChannelSubMerchCode());//微信子商户号
		return order;
	}
	
	
	
	public List<TradeOrder> selecSuccessTradeOrder() {
		return TradeOrder.dao.find("select * from trade_order where settleDate=? and payType=? and orderStatus=?", FSDate.getDate(), PayType.TRANSFER_QRCODE, OrderStatus.Success.getValue());
	}
	
	
	public TradeOrder selecSuccessTradeOrderFirstDate(String merchCode){
		String minDate = "SELECT MIN(createTime) FROM trade_order WHERE orderStatus='TS' AND merchCode='"+merchCode + "'"
				+ " AND channelCode='wxgipay'"
				+ " AND amount>100";
		
		return TradeOrder.dao.findFirst("SELECT * FROM trade_order WHERE  orderStatus='TS' AND "
				+ "merchCode='" + merchCode + "'" + " AND " 
				+"channelCode='wxgipay'  AND " + "amount>100 AND " +
				"createTime = (" + minDate + ")");
		
		
		
		
//		return TradeOrder.dao.findFirst("select *, min(settleDate) from trade_order where merchCode=? and orderStatus=?"
//				+ "and channelCode=?", 
//				merchCode, OrderStatus.Success.getValue(), "wxgipay");
//			
	}
	
	
	public TradeOrder selecSuccessTradeOrderEndDate(String merchCode){

		String minDate = "SELECT MAX(createTime) FROM trade_order WHERE orderStatus='TS' AND merchCode='" + merchCode + "'"
				+" AND channelCode='wxgipay'"
				+ " AND amount>100";
		
		return TradeOrder.dao.findFirst("SELECT * FROM trade_order WHERE  orderStatus='TS' AND "
				+"channelCode='wxgipay'  AND "
				+ "merchCode='" + merchCode + "'" + " AND " + "amount>100 AND " +
				"createTime = (" + minDate + ")");
		
		
		
		//		return TradeOrder.dao.findFirst("select *, max(settleDate) from trade_order where merchCode=? and orderStatus=?"
//				+ "and channelCode=?", 
//				merchCode, OrderStatus.Success.getValue(), "wxgipay");
//		
	}
	
	
	public List<TradeOrder> selecCreateTradeOrder() {
		return TradeOrder.dao.find("select * from trade_order where settleDate=? and payType=? and orderStatus=?", FSDate.getDate(), PayType.TRANSFER_QRCODE, OrderStatus.Create.getValue());
	}

	public long sumAmount(String otherMerchCode, String settleDate) {
		String sql = "select sum(amount) from trade_order where otherMerchCode = ? and settleDate = ? and orderStatus = ?";
		BigDecimal sumAmount = Db.queryBigDecimal(sql, otherMerchCode, settleDate, OrderStatus.Success.getValue());
		if(sumAmount == null) {
			sumAmount = BigDecimal.ZERO;
		}
		return sumAmount.longValue();
	}
	
}
